package com.lagou.edu.content;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.MyAutowired;
import com.lagou.edu.annotation.MyComponent;
import com.lagou.edu.annotation.MyTransactional;
import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.utils.MyClassUtils;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MyApplicationContext {

    private String path;

    private Map<String, Object> myBeans = null;

    public MyApplicationContext(String path) throws Exception{
        // 给包path赋值
        this.path = path;

        // 创建一个map
        myBeans = new HashMap<String, Object>();

        // 1. 解析@MyComponent标签，初始化有@MyCompone注解的bean，这个时候只是初始化，未做属性赋值
        initBeans();

        // 2. 属性赋值，解析@MyAutowired
        setBeans();

        // 3. 设置动态代理，解析@MyTransactional
        setProxy();

    }

    private void setProxy() {
        Iterator<Map.Entry<String, Object>> iterator = myBeans.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            String key = entry.getKey();
            Object myBean = myBeans.get(key);

            // 判断是否有@MyTransactional注解
            MyTransactional annotation = myBean.getClass().getAnnotation(MyTransactional.class);
            if (annotation != null) {
                String proxyFactoryBeanId = toLowerCaseFristOne(ProxyFactory.class.getSimpleName());

                ProxyFactory proxyFactory = (ProxyFactory)myBeans.get(proxyFactoryBeanId);

                Class<?>[] interfaces = myBean.getClass().getInterfaces();
                // 判断当前类是否实现接口
                Object proxyBean = null;
                if (interfaces.length > 0) {
                    // 实现了接口，使用jdk动态代理
                    proxyBean = proxyFactory.getJdkProxy(myBean);
                } else {
                    // 没有实现接口，使用cglib动态代理
                    proxyBean = proxyFactory.getCglibProxy(myBean);
                }
                myBeans.put(key, proxyBean);
            }
        }
    }

    private void setBeans() throws IllegalAccessException {
        for (Object obj : myBeans.values()) {
            setFiled(obj);
        }
    }

    public void setFiled(Object obj) throws IllegalAccessException {
        // 获取当前类的所有属性
        Field[] declaredFields = obj.getClass().getDeclaredFields();

        for (Field declaredField : declaredFields) {
            // 获取的是有@MyAutowired标签的属性
            MyAutowired annotation = declaredField.getAnnotation(MyAutowired.class);
            if (annotation != null) {
                String beanId = annotation.value();
                if (StringUtils.isEmpty(beanId)) {
                    beanId = toLowerCaseFristOne(declaredField.getName());
                }
                Object myBean = myBeans.get(beanId);
                if (myBean != null){
                    declaredField.setAccessible(true);
                    declaredField.set(obj,myBean);
                }
            }
        }

    }

    private void initBeans() throws IllegalAccessException, InstantiationException {
        // 获取path下所有的类
        List<Class<?>> classes = MyClassUtils.getClasses(path);

        // 遍历
        for (Class<?> aClass : classes) {
            // 判断是否有定义的@MyComponet的标签
            MyComponent annotation = aClass.getAnnotation(MyComponent.class);
            if (annotation != null) {
                String beanId = annotation.value();
                // 判断value是否值，如果有值，value作为beanId
                if (StringUtils.isEmpty(beanId)) {
                    // value没有值，判断当前类是否实现了接口，没有实现接口的话，取当前类名首字母小写
                    // 如果实现了接口，取接口名首字母小写
                    Class<?>[] interfaces = aClass.getInterfaces();
                    if(interfaces == null || interfaces.length == 0) {
                        beanId = toLowerCaseFristOne(aClass.getSimpleName());
                        myBeans.put(beanId, aClass.newInstance());
                    } else {
                        for (Class<?> anInterface : interfaces) {
                            beanId = toLowerCaseFristOne(anInterface.getSimpleName());
                            myBeans.put(beanId, aClass.newInstance());
                        }
                    }
                } else {
                    myBeans.put(beanId, aClass.newInstance());
                }
            }
        }
    }

    private static String toLowerCaseFristOne(String str) {
        if (Character.isLowerCase(str.charAt(0))) {
            return str;
        } else {
           return new StringBuilder().append(Character.toLowerCase(str.charAt(0))).append(str.substring(1)).toString();
        }
    }
}
